package com.tuanzi.loan.business.service.system.impl;

import java.util.List;
import java.util.Objects;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.retry.RetryException;
import org.springframework.retry.annotation.Retryable;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.tuanzi.loan.business.constants.DictionaryCode;
import com.tuanzi.loan.business.entity.CurrentUser;
import com.tuanzi.loan.business.entity.system.Partner;
import com.tuanzi.loan.business.entity.system.SystemUser;
import com.tuanzi.loan.business.repository.system.SystemUserRepository;
import com.tuanzi.loan.business.service.system.DictionaryService;
import com.tuanzi.loan.business.service.system.PartnerService;
import com.tuanzi.loan.business.service.system.SystemUserService;
import com.tuanzi.loan.core.aspect.Debug;
import com.tuanzi.loan.core.exception.SystemException;
import com.tuanzi.loan.core.repository.JPABaseRepository;
import com.tuanzi.loan.core.service.BaseServiceImpl;
import com.tuanzi.loan.core.vo.PageSearcher;
import com.tuanzi.loan.vo.request.system.SystemUserSearchRequest;
import com.tuanzi.loan.vo.response.system.SystemUserSearchResponse;

import lombok.extern.slf4j.Slf4j;

/**
 * @author Ray 2017/09/21
 */
@Debug
@Slf4j
@Service
@Transactional
@Retryable(value = { RetryException.class })
public class SystemUserServiceImpl extends BaseServiceImpl<SystemUser, String> implements SystemUserService {

	@Autowired
	private SystemUserRepository systemUserRepository;
	@Autowired
	private DictionaryService dictionaryService;
	@Autowired
	private PartnerService partnerService;
	@Autowired
	private PasswordEncoder passwordEncoder;

	@Override
	protected JPABaseRepository<SystemUser, String> getRepository() {
		return systemUserRepository;
	}

	@Override
	public SystemUser findOneByAccount(String account) {
		return systemUserRepository.findByAccount(account);
	}

	public Page<SystemUserSearchResponse> list(PageSearcher<SystemUserSearchRequest> pageSearcher) {
		return systemUserRepository.list(pageSearcher.getSearchCondition(), pageSearcher.getPageable());
	}

	@Override
	public SystemUser saveOrUpdate(SystemUser user) {
		if (user.getId() == null) {
			user.setRetryTimes(0);
			user.setLocked(false);
			user.setPwd(getDefaultPassword());
		}

		return super.saveOrUpdate(user);
	}

	@Override
	public void resetPassword(String userId) {
		SystemUser user = systemUserRepository.findOne(userId);
		user.setPwd(getDefaultPassword());
		this.saveOrUpdate(user);
	}

	private String getDefaultPassword() {
		String defaultPwd = dictionaryService.findByCode(DictionaryCode.DEFAULT_USER_PWD).getValue1();
		return passwordEncoder.encode(defaultPwd);
	}

	@Override
	public List<SystemUser> findAllByPartnerId(String partnerId) {
		return systemUserRepository.findAllByPartnerId(partnerId);
	}

	@Override
	public SystemUser enable(SystemUser user) {
		Partner partner = partnerService.findOne(user.getPartnerId());
		if (!partner.getEnable()) {
			throw new SystemException("用户所属合作机构为禁用状态,不能启用该用户");
		}
		return super.enable(user);
	}

	@Override
	public void increseRetryTimes(String username) {
		SystemUser user = findOneByAccount(username);
		if (user != null) {
			if (user.getRetryTimes() >= 3) {
				user.setLocked(true);
			} else {
				user.setRetryTimes(user.getRetryTimes() + 1);
			}
			saveOrUpdate(user);
		}
	}

	@Override
	public SystemUser unlock(String id) {
		SystemUser user = findOne(id);
		user.setLocked(false);
		user.setRetryTimes(0);
		return saveOrUpdate(user);
	}

	@Override
	public void updateLastLoginTimeAndResetRetryTimes(String account) {
		systemUserRepository.updateLastLoginTimeAndResetRetryTimes(account);
	}

	@Override
	public void changePassword(String oldPassword, String newPassword, String confirmPassword) {
		SystemUser systemUser = systemUserRepository.findOne(CurrentUser.get().getUserId());
		if (systemUser == null) {
			RuntimeException e = new SystemException("未能找到该用户");
			log.warn(e.getMessage(), e);
			throw e;
		}

		if (!passwordEncoder.matches(oldPassword, systemUser.getPwd())) {
			throw new SystemException("原密码错误");
		}

		if (StringUtils.length(newPassword) < 8) {
			throw new SystemException("密码长度最少8位");
		}

		if (!newPassword.equals(confirmPassword)) {
			throw new SystemException("新密码和确认新密码不一致");
		}

		systemUser.setPwd(passwordEncoder.encode(newPassword));
		systemUserRepository.save(systemUser);
	}

	@Override
	public List<SystemUser> findAllByRoleCode(String roleCode) {
		return systemUserRepository.findAllByRoleCode(roleCode);
	}

	@Override
	public boolean existByAccount(String account) {
		return systemUserRepository.countByAccount(account) > 0;
	}

	@Override
	public String findNameByAccount(String account) {
		if (StringUtils.isBlank(account)) {
			return StringUtils.EMPTY;
		}

		SystemUser systemUser = findOneByAccount(account);

		if (systemUser != null) {
			return systemUser.getName();
		}

		log.warn("不存在用户: {}", account);
		return StringUtils.EMPTY;
	}

	@Override
	public List<SystemUser> findAllByAccounts(List<String> accounts) {
		return systemUserRepository.findAllByAccountIn(accounts);
	}

	@Override
	public List<SystemUser> findAllHasEmailSystemUser() {
		return systemUserRepository.findAllByEmailIsNotNull();
	}

	@Override
	public boolean isUseDefaultPassword(String account) {
		String defaultPlainTextPassword = dictionaryService.findByCode(DictionaryCode.DEFAULT_USER_PWD).getValue1();
		SystemUser systemUser = systemUserRepository.findByAccount(account);
		if(Objects.isNull(systemUser)) {
			throw new SystemException("未能找到该用户");
		}
		String password = systemUser.getPwd();
		if(passwordEncoder.matches(defaultPlainTextPassword, password)){
			return true;
		}
		return false;
	}
}
